//安装 npm install h264-sps-parser

import {parse} from "h264-sps-parser";

export class H264Helper {

  static getFrameTypes(h264Data: Uint8Array): string[] {
    const typeNumbers = this.getFrameTypeNumbers(h264Data);
    if (typeNumbers.length === 0) {
      return ['没有合法的NAL单元起始码'];
    }
    const desc = []
    for (let i = 0; i < typeNumbers.length; i++) {
      switch (typeNumbers[i]) {
        case 1:
          desc.push('I 帧（关键帧，自包含数据，不依赖前后帧）');
          continue;
        case 2:
          desc.push('P 帧（预测编码帧，依赖前面的帧）');
          continue;
        case 3:
          desc.push('B 帧（DPB，是双向预测编码帧，依赖于之前和之后的帧）');
          continue;
        case 4:
          desc.push('AUD 帧（不是实际的视频帧，用于流的结构化和帧的边界标记数）');
          continue;
        case 5:
          desc.push('IDR 帧（特殊的I帧，解码器重置点）');
          continue;
        case 6:
          desc.push('SEI 帧（补充增强信息）');
          continue;
        case 7:
          desc.push('SPS 帧（序列参数集，包含全局编码参数）');
          continue;
        case 8:
          desc.push('PPS 帧（图像参数集，包含帧级编码参数）');
          continue;
        case 9:
          desc.push('AUD 帧（不是实际的视频帧，用于流的结构化和帧的边界标记数）');
          continue;
        case 10:
          desc.push('EOSeq（序列结尾）');
          continue;
        case 11:
          desc.push('EOStream（流结尾）');
          continue;
        case 12:
          desc.push('填充数据');
          continue;
        case 13:
          desc.push('SPS扩展');
          continue;
        case 14:
          desc.push('前缀NAL单元');
          continue;
        case 15:
          desc.push('子SPS');
          continue;
        case 19:
          desc.push('辅助编码条带');
          continue;
        case 20:
          desc.push('条带扩展');
          continue;
        default:
          desc.push(`未知NAL单元类型(${typeNumbers[i]})`);
      }
    }
    return desc
  }

  static getFrameTypeNumbers(h264Data: Uint8Array): number[] {
    const number = []
    for (let i = 0; i < h264Data.length - 5; i++) {
      let byte = 0
      if (h264Data[i] === 0 && h264Data[i + 1] === 0 && h264Data[i + 2] === 1) {
        byte = h264Data[i + 3]
      } else if (h264Data[i] === 0 && h264Data[i + 1] === 0 && h264Data[i + 2] === 0 && h264Data[i + 3] === 1) {
        byte = h264Data[i + 4]
      }
      number.push(byte & 0x1f) // 获取NAL单元类型(低5位)
    }
    return number
  }

  static getPSPInfo(spsUnit: Uint8Array) {
    if (spsUnit[0] === 0 && spsUnit[1] === 0) {
      spsUnit = spsUnit.slice(4)
    }
    return parse(spsUnit);
  }

  static getResolution(spsUnit: Uint8Array): { width: number, height: number } | null {
    const spsInfo = this.getPSPInfo(spsUnit);
    if (spsInfo) {
      return {
        width: spsInfo.pic_width_in_mbs * 16,
        height: spsInfo.pic_height_in_map_units * 16
      };
    }
    return null;
  }
}